home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 2000 November: Tool Chest / Dev.CD Nov 00 TC Disk 1.toast / Sample Code / Archive / Graphics / QuickDraw GX / IW-Half-Dither / !IW-Half-Dither Read Me next >
Encoding:
Text File  |  2000-09-28  |  21.2 KB  |  386 lines  |  [TEXT/ttxt]

  1. IW-Half-Dither GX Printer Driver
  2.  
  3. Driver Modified by Don Swatman, Developer Technical Support
  4. CodeWarrior build by Jason Hodges-Harris, Developer Technical Support
  5.  
  6. Copyright: © 1996 by Apple Computer, Inc. All rights reserved.
  7.  
  8.  
  9. What it does
  10.  
  11. "IW-Half-Dither" is a GX printer driver designed to allow an ImageWriter II to render and print in halftone using the 'rdip' resource. It is based on the sample driver source found in :
  12.  
  13. "Dev.CD July 96 MacOS SDK2:Development Kits (Disc 2):QuickDraw™ GX:Programming Stuff:Sample Code:Printing Samples:Printer Drivers…:ImageWriter:"
  14.  
  15. It makes use of the in built rendering abilities of QuickDraw GX.
  16.  
  17. In addition, it demonstrates :
  18.     - How to change the settings generated by the 'rdip' on the fly so that it is possible to switch between dithering and half toning 
  19.         with one driver.
  20.     - How to add and manage multiple panels to a print dialog.
  21.     - How to map a gxExtendedDITLType('xdtl') resource to a collection item.
  22.     - How to switch color planes on and off.
  23.  
  24. It's not intended to be a definitive 'document' on how to implement these features, but illustrates one way of doing it.  
  25.  
  26. How to use the driver
  27.  
  28. Installation
  29.  
  30. Make sure QuickDraw GX is installed, drag the "IW-Half-Dither" extension over the system folder. It should automatically be moved into the extensions folder. Restart the Macintosh.
  31.  
  32. Go to the Chooser and select the "IW-Half-Dither". Create a desktop printer appropriate to how your ImageWriter is connected to your computer.
  33.  
  34. When you next print from a GX aware application, the print dialog should now have two new panels: separations and rendering.
  35.  
  36. General
  37.  
  38. "IW-Half-Dither" works like the standard ImageWriter driver except that it defaults to half tone rendering instead of dither and it has two extra panels in the print dialog. These two panels allow the user more control over how the final image appears from the ImageWriter 
  39.  
  40.  
  41. Separations Panel
  42.  
  43. This panel contains 4 check boxes - one for each CMYK plane. Clicking them on or off determines which planes the printer will print.There is more information later in the Read Me that describes how this is done.
  44.  
  45. Rendering Panel
  46.  
  47. This panel controls how the image is rendered. There are two modes - dither and halftone. These are set by clicking in the appropriate radio button. In dither mode, there is only one option "Dither Level". This is a popup menu which gives a range of 1-16. The effect of changing this value is described in "Inside Macintosh : Quickdraw GX - Objects" Pages 7-11 to 7-12. In half tone mode, you can change the "Dot shape" globally and the angle and frequency for each color. The angle takes a floating point number in degrees and the frequency refers to dots per inch.
  48.  
  49. Building
  50.  
  51. MPW build notes
  52.  
  53. This printer driver builds using the latest release of the MPW environment (currently 20), using the below command line when the current directory is set to that of the printer driver.
  54.  
  55.     BuildProgram -e IW-Half-Dither
  56.  
  57.  
  58. Please note that before building the printer driver the following steps have to be taken:
  59.  
  60. *    Insert the Mac OS SDK containing the QuickDraw GX SDK, (currently the Dev CD July 96 MacOS SDK2).
  61.  
  62. *    Copy the GXLibraries folder from the 'Development Kits (Disc2):QuickDraw™GX:Programming Stuff:' folder and place it into the :MPW:Libraries: folder.
  63.  
  64.  
  65. CodeWarrior build notes
  66.  
  67. To build the printer driver the following steps have to be taken:
  68.  
  69. *    First, build the IWriterChooserPACK.µ project as this contains all of the driver resource .r files for the projects and also creates the target file if not present.
  70.  
  71. *    Second, build the ImageWriterGX68k.µ, ImageWriterGXNew68k.µ and IWriterChooserLDEF.µ projects in any order. These are automatically merged into the target file during linking.
  72.  
  73. Please note that the project files to build the printer driver are for CodeWarrior 8 and whilst the code should compile in earlier versions, projects aren't supplied as the Rez compiler plug-in is necessary and is supplied starting with CodeWarrior release 8. 
  74.  
  75.  
  76. How the interesting stuff works
  77.  
  78. Modifications to the gxRasterPrefsType('rdip') resource for half toning
  79.  
  80. The gxRasterPrefsType or 'rdip' resource can be found in NewApp.r. In its original format it is setup for dithering. This default already produces a good quality of output on the ImageWriter II; however, this sample is meant to demonstrate how to add half toning. The top part of the 'rdip' does not need any alteration and can remain the same for both half-toning and dithering:
  81.  
  82.     resource gxRasterPrefsType (gxRasterPrefsID, sysheap, purgeable)
  83.     {
  84.         gxDefaultRaster,        // default options are fine
  85.     
  86.         0x00900000,    0x00900000,    // 144X144 dpi device
  87.         16,                                 // min band size == 2 head heights
  88.         0,                                  // max band size (0 is full page)
  89.         0x00008000,             // RAM percentage (50%)
  90.         100*1024,               // RAM slop (100K)
  91.         4,                      // 4 bit device
  92.  
  93. These are general setup instructions for the renderer and don't need to be altered. The changes come in the next section - the plane array. As each plane is changed in roughly the same way, I'll only describe the first.
  94.  
  95.         gxDefaultOffscreen,        // YELLOW plane.  Use default half-toning.
  96.         0x000F0000,                // Angle = 15 degrees
  97.         0x002D0000,                // Freq = 45
  98.         gxRoundDot,                // RoundDot
  99.         gxComponent3Tint,          // Extract yellow and dither it
  100.         gxRGBSpace, gxNoProfile, 0, 0, 0, 0,                // DotColor == black
  101.         gxRGBSpace, gxNoProfile, 0xFFFF, 0xFFFF, 0xFFFF, 0, // Background color == white
  102.         gxCMYKSpace,               // Convert to gxCMYKSpace before half-toning.
  103.         gxNoSpace,                 // No explicit color space
  104.         gxNoSet,                   // No color set
  105.         gxNoProfile,               // No profile specified
  106.  
  107. Plane flags = gxDefaultOffscreen - This will make the render use the default halftoning.
  108. Angle       =    0x000F0000         - This is a fixed point value which refers to the angle in degrees used for
  109.                                    halftoning. This should be varied for each plane. In this case it is an angle
  110.                                    of 15 degrees
  111. Frequency   = 0x002D0000         - This is the number of cells per inch. In this case 45 cells per inch. It is a
  112.                                    fixed point value.
  113. Dither type = gxRoundDot         - This is the shape of the dot. The render can produce dots of different
  114.                                    shapes which produce different effects.
  115. Tint Type   = gxComponent3Tint   - This is the tinting that we are going to apply to this plane.
  116.                                    The constants for CMYK half-toning are:
  117.                                      Cyan       gxComponent1Tint
  118.                                      Magenta    gxComponent2Tint
  119.                                      Yellow     gxComponent3Tint
  120.                                      Black      gxComponent4Tint
  121.                                    As we print yellow first, the first planes tint type is gxComponent3Tint.
  122. Dot Color and Background Color   - These are the dot colors that are used in this plane. They are set to black
  123.                                    dot and white background respectively.
  124. Tint Space = gxCMYKSpace         - This will cause the render to convert the colors to CMYK space before
  125.                                    rendering.
  126. Plane Color Space   =    gxNoSpace  - This is the color space of the original plane. We don't need to set it.
  127. Plane Color Set     =    gxNoSet    - This is the resource ID of a color set to use for the plane. We don't need
  128.                                    to set this.
  129. Plane Color Profile =    gxNoProfile- This is the resource ID of a color profile to use for the plane. In this case, 
  130.                                    we don't supply one.
  131.  
  132. The other planes are created in the same way except they have different angles and the appropriate tint type. The other difference from the ImageWriter sample driver this was based on, is that you no longer need gxColorSetResType('crst') resource.
  133.  
  134.  
  135. Changing the rendering settings on the fly
  136.  
  137. It is not possible to change how a GX driver renders by simply patching the 'rdip'. However, there is a way of doing this by overriding the universal image message, GXSetupImageData. This message allows you to alter the initialization information about a printer; therefore, the type of data passed to it can vary depending on what type of driver it is. Also it is worth noting that when it is called, the information has not necessarily been read in. Therefore the first thing your override must do is to forward the message so that the default values are read in. In the case of a raster driver, it is passed a gxRasterImageDataHdl. The routine in the sample is called SD_SetupImageData().
  138.  
  139.     OSErr SD_SetupImageData ( gxRasterImageDataHdl hImageData )
  140.     {
  141.            OSErr                        anErr;
  142.  
  143.         anErr = Forward_GXSetupImageData ( hImageData );
  144.         nrequire ( anErr, Forward_GXSetupImageData );
  145.  
  146.     // Do my cool stuff here
  147.  
  148.     Forward_GXSetupImageData:
  149.         return anErr;
  150.     }
  151.  
  152. An override for a raster printer is passed a gxRasterImageDataHdl. This contains information about how the planes are setup in a very similar format to the 'rdip'. As rendering has not happened at this stage, it is possible to make changes to this information and therefore allow the user to have a great deal of control over the rendering.
  153.  
  154. The override in "IW-Half-Dither" does all the normal things the previous driver did; in other words do any required setting up for rough and text modes, whether accurate bit alignment is setup and if the user has put a black and white ribbon in the printer. Having done this, the function then makes changes to the theSetup.planeSetup[] array as appropriate. The information that it puts in here comes from a custom collection kCMYKRenderCollectionType('Dipy'). If the collection doesn't exist, then it does no further processing and uses the information from the 'rdip' resource. The 'Dipy' collection is just there as an example and you should create and use your own. It modifies and sets up the fields in the planeSetup[] array so that it can either produce a halftone or a dither render; because of this it must clear fields that are used by one and not the other. In the case of dither it must also create a color set to be put into the planeSet field.
  155.  
  156. Switching color planes on and off
  157.  
  158. The easiest way of achieving this is to make changes to GXRasterPackageBitmap message to only allow the printer to print the colors you want.  This is done in "IW-Half-Dither" by the routine
  159.  
  160.     OSErr SD_PackageBitmap (
  161.                 gxRasterPackageBitmapRec    *pPackage,
  162.                    Ptr                      buffer,        // data goes here + bufferPos
  163.                 unsigned long            *bufferPos,    // how much of the buffer already is full
  164.                 gxRasterImageDataHdl     hImageData )
  165.  
  166. This function is called once per printer head pass. As the ImageWriter interlaces its head pattern, it has to make two head passes per color band. This causes the head to print a color, move the paper down a small amount, do the second pass, then move the paper back ready for the next color. This causes the paper to do a certain amount of "dancing". To avoid this the printer stores up line feeds for blank lines. These are put in the buffer then removed if no printing occurred and stored up. After sending the line feeds, it checks to see if it is really making four passes and whether it should be printing this band:
  167.  
  168.     if (   (  (*hImageData)->packagingInfo.colorPasses == 4)
  169.         && (! PrintThisBand ( pPackage->colorBand )) )
  170.         bandIsDirty = false;
  171.     else
  172.     {
  173.         // Work out if the band is dirty - has pixels that need printing
  174.     }
  175.  
  176. PrintThisBand uses the 'Dipy' collection to see if the current band needs to be printed. The collection contains a set of booleans -one for each plane- that control if the plane should be printed. After either checking to see if the band is dirty, it the either prints it or strips out the entered line feeds before returning.
  177.  
  178. The kCMYKRenderCollectionType('Dipy') collection
  179.  
  180.     struct CMYKRenderCollection
  181.     {
  182.     // Plane flags, set to true to print the plane
  183.         unsigned char cyanIsOn;
  184.         unsigned char magentaIsOn;
  185.         unsigned char yellowIsOn;
  186.         unsigned char blackIsOn;
  187.  
  188.     // Set to "kDitherIt" for dithered output, or "kHalfToneIt" for half tone
  189.         unsigned char renderMode;
  190.         unsigned char fill1;
  191.  
  192.     // used when in dither mode to select the level of dither
  193.         short ditherLevel;
  194.  
  195.     // used when in half tone mode to select how to half tone
  196.         short dotType;
  197.         Fixed angles[4];
  198.         Fixed frequency[4];
  199.  
  200.     };
  201.     typedef struct CMYKRenderCollection CMYKRenderCollection;
  202.  
  203. This can be used in conjunction with the overrides described above to give the user control of the rendering. The byte alignment is such that it can be accessed by a gxExtendedDITLType('xdtl') resource. The plane flags are used to turn planes on or off. 
  204.  
  205. cyanIsOn, magentaIsOn,
  206. yellowIsOn, blackIsOn  - Turns planes on or off
  207. renderMode             - Takes one of two constants to decide whether it should dither or half tone:
  208.                             #define kDitherIt   0
  209.                             #define kHalfToneIt 1
  210. ditherLevel            - This is used in dither mode.
  211. dotType                - This is used during half-toning to control the type of dot.
  212. angles[],frequency[]   - These are used in half-toning to control the rendering. They take the following
  213.                          constants :
  214.                             #define kRenderOptsCyan    0
  215.                             #define kRenderOptsMagenta 1
  216.                             #define kRenderOptsYellow  2
  217.                             #define kRenderOptsBlack   3
  218.  
  219. Adding multiple panels to the print dialog
  220.  
  221. To add panels to the dialog you need to several things. First you must create a DITL . The (0,0) origin for it is considered to be the top left of the panel.  You should also create a icon family. These will be used in the list on the left of the panel. To connect these together you need to create a gxPrintPanelType('ppnl') resource. This resource is used to connect the DITL and the icons together. It also contains the name of the panel which is displayed underneath the icon.
  222.  
  223.     resource gxPrintPanelType (kSeperationPanelID, sysheap, purgeable)
  224.     {
  225.         "Separations",        // the panel name
  226.         smRoman,              // script id
  227.         kSeperationPanelID,   // the icon id
  228.         kSeperationPanelID    // the DITL id
  229.     };
  230.  
  231. To install a panel you have to provide an override to the GXJobPrintDialog message. This is done in the sample by SD_JobPrintDialog().
  232.  
  233.     OSErr SD_JobPrintDialog(gxDialogResult *dlogResult )
  234.     {
  235.         OSErr theErr = noErr;
  236.  
  237.         theErr = SetUpPrintPanel( ); 
  238.     
  239.         if (!theErr)
  240.             theErr = Forward_GXJobPrintDialog(dlogResult);
  241.  
  242.         return theErr;
  243.     }
  244.  
  245. SetUpPrintPanel() checks to see if the render options collection exists. If it doesn't then it creates one and adds it to the jobs collection. Next the panels are added.
  246.  
  247.     gxPanelSetupRecord panelSetupRec;
  248.  
  249.     panelSetupRec.panelResId     = kSeperationPanelID;
  250.     panelSetupRec.resourceRefNum = GXGetMessageHandlerResFile();
  251.     panelSetupRec.refCon         = 0;
  252.     panelSetupRec.panelKind      = gxDriverPanel;
  253.  
  254.     theErr                       = GXSetupDialogPanel(&panelSetupRec);
  255.  
  256. As two panels are added, the above block of code is repeated twice with a different panelResID.
  257.  
  258. If every active item in your panel is mapped to a collection by a 'xdtl' resource, then you need to do nothing more. However in the "Render" panel, clicking the dither or the halftone button causes items to gray out. Smart though the 'xdtl' is. You can't get it handle this and you must do a little more work.  Again you must override a message; this time the GXHandlePanelEvent is overridden by SD_HandlePanelEvent. This function is called and passed gxPanelInfoRecord for every panel that the driver is installed. Therefore it needs to check the panelResId parameter in the passed gxPanelInfoRecord too check which one of the two panels is being sent events. If the event passed in panelEvt was a gxPanelHitEvt, then you can find out which item was clicked by subtracting itemCount  from itemHit. This will give you the item number in the DITL. For example
  259.  
  260.     #define kDitherRB   1
  261.     #define kHalfToneRB 2
  262.  
  263.     OSErr SD_HandlePanelEvent( gxPanelInfoRecord *panelInfo )
  264.     {
  265.         OSErr                   theErr = noErr;
  266.         GrafPtr                 oldPort;
  267.         DialogPtr               pDlg;
  268.  
  269.         pDlg = panelInfo->pDlg;
  270.  
  271.         GetPort(&oldPort);
  272.         SetPort(pDlg);
  273.     
  274.         switch (panelInfo->panelEvt)
  275.         {
  276.  
  277.             case gxPanelHitEvt:
  278.                 if (panelInfo->panelResId == kDitherPanelID)
  279.                 {
  280.                    switch (panelInfo->itemHit - panelInfo->itemCount)
  281.                    {
  282.                        case kDitherRB:
  283.                            // Do Something
  284.                        case kHalfToneRB:
  285.                            // Do Something
  286.                            break;
  287.                     }
  288.                 }
  289.                 break;
  290.  
  291.             case gxPanelOpenEvt:
  292.             ...
  293.  
  294.  
  295. Mapping a gxExtendedDITLType('xdtl') resource to a collection item
  296.  
  297. gxExtendedDITLType('xdtl') resource allows you to map a collection directly to your DITL in a print panel, however it requires that certain things are true about the alignment of the collection. "IW-Half-Dither" uses four types which will be described below.
  298.  
  299.     Booleans
  300. In the collection these should be "unsigned chars" and are set to 0 or 1 for on or of. They can  be byte aligned. In the resource file you need to add a line such as:
  301.  
  302.     CheckBox {   kCMYKRenderCollectionType, kCMYKRenderCollectionID, 0, 1}
  303. or
  304.     CheckBox {   'Dipy', 0, 0, 1}
  305.  
  306. 1st Parameter - The collection type
  307. 2nd Parameter - The collection ID
  308. 3rd Parameter - The byte offset into the collection to an unsigned chars
  309. 4th Parameter - The DITL item number
  310.  
  311.     RadioButtons
  312. There should only be one parameter( an "unsigned chars") in the collection and this takes values from 0  to the last button-1. It should  be word aligned. In the resource file you need to add a line such as:
  313.  
  314.         RadioButtons     {    kCMYKRenderCollectionType, kCMYKRenderCollectionID, 4, {1,2}}
  315.  
  316. 1st Parameter - The collection type
  317. 2nd Parameter - The collection ID
  318. 3rd Parameter - The byte offset into the collection to an unsigned chars
  319. 4th Parameter, onwards - The DITL item numbers of the radio buttons
  320.  
  321.     Pop-Up Menus
  322. There should only be a short in the collection that stores the current values of the pop-up menu. It should  be word aligned. In the resource file you need to add a line such as:
  323.  
  324.     PopUp {    kCMYKRenderCollectionType, kCMYKRenderCollectionID, 6, 3},
  325.  
  326. 1st Parameter - The collection type
  327. 2nd Parameter - The collection ID
  328. 3rd Parameter - The byte offset into the collection to a short
  329. 4th Parameter - The DITL item number of a control.
  330.  
  331.     Fixed point string
  332. This is used to enter map a Fixed value in the collection to a text edit. It should  be word aligned. In the resource file you need to add a line such as:
  333.  
  334.     EditTextReal     {   kCMYKRenderCollectionType, kCMYKRenderCollectionID, 10, 5,
  335.                       1,"0.0","360.0"},
  336.   
  337. 1st Parameter - The collection type
  338. 2nd Parameter - The collection ID
  339. 3rd Parameter - The byte offset into the collection to a Fixed
  340. 4th Parameter - The DITL item number of a text edit item.
  341. 5th Parameter - This takes a 1 or a 0 to indicate whether the text is highlighted or not
  342. 6th Parameter - A string to indicate the lowest value it can take. In the above case 0
  343. 7th Parameter -  A string to indicate the highest value it can take. In the above case 360.0
  344.  
  345.         
  346.  
  347. Further things YOU could do
  348.  
  349. If you feel like playing with this driver, there're a few ways you could improve it.
  350.     - Add ColorSync support
  351.     - Stop the printer 'dancing' if the scan line contains some data (in other words it is dirty) but the color is not being printed.
  352.  
  353. References
  354.  
  355. Inside Macintosh : QuickDraw GX Printing Extensions and Drivers
  356.     "The Raster Preferences ('rdip') Resource" Pages 6-66 to 6-72
  357.     "GXSetupImageData" Pages 4-92 to 4-93
  358.     "GXRasterPackageBitmap" Pages 4-100 to 4-101
  359.  
  360. Inside Macintosh : QuickDraw GX Printing
  361.     "xdtl" Pages 3-128 to 3-132
  362.     "The Dialog Box Panel Resource" Page 3-24
  363.  
  364. Inside Macintosh : QuickDraw GX Objects
  365.     "Dither" Pages 7-10 to 7-13
  366.     "Halftone" Pages 7-13 to 7-17
  367.  
  368.  
  369. *********************************************************************
  370. **                                                                 **
  371. ** You may incorporate this sample code into your applications     **
  372. ** without restriction, though the sample code has been provided   **
  373. ** "AS IS" and the responsibility for its operation is 100% yours. **
  374. ** However, what you are not permitted to do is to redistribute    **
  375. ** the source as "DSC Sample Code" after having made changes. If   **
  376. ** you're going to re-distribute the source, we require that you   **
  377. ** make it clear in the source that the code was descended from    **
  378. ** Apple Sample Code, but that you've made changes.                **
  379. **                                                                 **
  380. *********************************************************************
  381.  
  382.  
  383. Don Swatman - May. 96
  384. © 1996 by Apple Computer, Inc., all rights reserved.
  385.  
  386.